#include "app_start.h"
#include "ecma.h"
#include "evm_type.h"
#include "evm_module_cffi.h"
#include "evm_module.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

extern evm_err_t evm_module_dlfcn(evm_t *e);

void evm_assert_fail (const char *assertion, const char *file, const char *function, const uint32_t line){
    evm_print ("AssertionError: '%s' failed at %s(%s):%lu.\n",
                       assertion,
                       file,
                       function,
                       (unsigned long) line);
}

char * vm_load_file(evm_t * e, char *filename){
    evm_filesystem_t *fs = evm_module_fs_getInstance();
    if(fs == NULL)
        return NULL;

    char *buffer = NULL;
    if(filename == NULL)
        return NULL;
    int filehandle = fs->open(filename, O_RDONLY | O_BINARY);
    if(filehandle < 0)
        return NULL;
    size_t fsize = fs->lseek(filehandle, 0, SEEK_END);
    fs->lseek(filehandle, 0, SEEK_SET);

    if(fsize>0)
    {
        evm_val_t * b = evm_buffer_create(e, sizeof(uint8_t)*fsize + 1);
        if( !b ) {
            fs->close(filehandle);
            return NULL;
        }
        buffer = (char*)evm_buffer_addr(b);
        memset(buffer, 0, fsize + 1);

        size_t ret = fs->read(filehandle, buffer, fsize);
        if(ret != fsize)
        {
            evm_print("read file content failed!\n");
            fs->close(filehandle);
            return NULL;
        }
        buffer[fsize] = 0;
    }
    fs->close(filehandle);
    return buffer;
}


const char * vm_load(evm_t * e, char * path, int type)
{
    EVM_UNUSED(type);
    int file_name_len = strlen(path) + 1;
    char* buffer = NULL;
    char * module_name = evm_malloc(file_name_len);
    if( !module_name )
        return NULL;
    sprintf(module_name, "%s", path);
    sprintf(e->file_name, "%s", path);
    buffer = vm_load_file(e, module_name);
    evm_free(module_name);
    return buffer;
}


#define evm_module_assert(err, s)         \
if (err != ec_ok ){ \
    evm_print(s); \
    return false; \
};\

static bool evm_load_module(evm_t *e)
{
    evm_err_t err = ecma_module(e);
    evm_module_assert(e->err, "failed to load ecma \r\n");

    err = evm_module_eventbus(e);
    evm_module_assert(err, "failed to load eventbus \r\n");

    err = evm_module_fs(e);
    evm_module_assert(err, "failed to load fs \r\n");

    err = evm_module_uart(e);
    evm_module_assert(err, "failed to load uart \r\n");

    err = evm_module_adc(e);
    evm_module_assert(err, "failed to load adc \r\n");

    err = evm_module_device(e);
    evm_module_assert(err, "failed to load device \r\n");

    err = evm_module_http(e);
    evm_module_assert(err, "failed to load http \r\n");

    err = evm_module_iic(e);
    evm_module_assert(err, "failed to load iic \r\n");

    err = evm_module_gpio(e);
    evm_module_assert(err, "failed to load pin \r\n");

    err = evm_module_pwm(e);
    evm_module_assert(err, "failed to load pwm \r\n");

    err = evm_module_rtc(e);
    evm_module_assert(err, "failed to load rtc \r\n");

    err = evm_module_sms(e);
    evm_module_assert(err, "failed to load sms \r\n");

    err = evm_module_spi(e);
    evm_module_assert(err, "failed to load spi \r\n");

    err = evm_module_builtin(e);
    evm_module_assert(err, "failed to load sys \r\n");

    err = evm_module_tcp(e);
    evm_module_assert(err, "failed to load tcp \r\n");

    err = evm_module_timer(e);
    evm_module_assert(err, "failed to load timer \r\n");

    err = evm_module_wdg(e);
    evm_module_assert(err, "failed to load wdg \r\n");

    err = evm_module_os(e);
    evm_module_assert(err, "failed to load os \r\n");

    err = evm_module_ffi(e);
    evm_module_assert(err, "failed to load ffi \r\n");

    err = evm_module_dlfcn(e);
    evm_module_assert(err, "failed to load dynamic library \r\n");

    return true;
}

int app_start(evm_t *e, const char* appfile)
{
    // 注册文件系统，evm虚拟机加载js脚本，依赖文件系统接口
    evm_module_fs_init();
    // js require函数在c的实现
    evm_register_file_load((intptr_t)vm_load);

    // 注册evm模块，将C实现的模块接口暴露给JS
    bool ret = evm_load_module(e);
    if(!ret)
        return -1;

    // 启动应用
    return evm_create(appfile);
}
